package com.nf.health.app.sweat.util;


import android.text.TextUtils;

import com.alibaba.fastjson.JSONObject;
import com.nf.health.app.sweat.bean.ParseDataBean;
import com.nf.health.app.sweat.bean.UploadBean;
import com.nf.health.app.utils.CRC8;
import com.nf.health.app.utils.DateUtil;
import com.nf.health.app.utils.LogUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import cn.bluetools.ProtocolParser;

/**
 * Created by he_pan on 2017/3/21.
 * The only genius that is worth anything is the genius for hard work
 *
 * @author he_pan
 */

public class SweatBluetoothUtils {
    public static int UP_MAX_CHANNEL = 13;//上身最大测量数
    public static int DOWN_MAX_CHANNEL = 7;//下身最大测量数

    /**
     * @param commandType 0 读取命令 1 设置采集频率
     * @param sampleFre   采集频率,当commandType为1时用到
     * @return 返回命令byte[]
     */
    public static byte[] getCommandByte(int commandType, int sampleFre) {
        if (sampleFre < 0 || sampleFre > 300) {
            return new byte[]{1};//
        }
        //现用集合记录,因为发送命令长度是不确定的
        ArrayList<Byte> writeByteList = new ArrayList<>();
        //1,包头NF0106
        writeByteList.add((byte) 0x4E);
        writeByteList.add((byte) 0x46);
        writeByteList.add((byte) 0x00);
        writeByteList.add((byte) 0x01);
        writeByteList.add((byte) 0x00);
        writeByteList.add((byte) 0x06);

        //2，通配地址  8字节AA
        for (int i = 0; i < 8; i++) {
            writeByteList.add((byte) 0xAA);
        }

        //3,当前时间 8字节
        byte nowTime[] = new byte[8];
        nowTime[0] = 0x7b;//{
        nowTime[7] = 0x7d;//}
        for (int i = 0; i < 6; i++) {
            nowTime[i + 1] = Byte.valueOf(DateUtil.date2String(new Date().getTime(), "yyMMddHHmmss").substring(i * 2, i * 2 + 2));
        }
        for (int i = 0; i < 8; i++) {
            writeByteList.add(nowTime[i]);
        }

        //4,标志位 1字节 0代表最后一帧，大于0时表示帧序号，且还有下一帧
        writeByteList.add((byte) 0x00);

        //5，命令 4字节
        if (commandType == SweatConfiguration.COMMAND_TYPE_READ_DATA) {
            writeByteList.add((byte) 0x00);
            writeByteList.add((byte) 0x03);
        } else if (commandType == SweatConfiguration.COMMAND_TYPE_SET_FREQ) {
            writeByteList.add((byte) 0x00);
            writeByteList.add((byte) 0x04);
        }

        //6 标识两位 0x00 0x00
        writeByteList.add((byte) 0x00);
        writeByteList.add((byte) 0x00);

        //命令数据 长度四位(固定) 数据位不固定
        if (commandType == SweatConfiguration.COMMAND_TYPE_READ_DATA) {//读取命令不用携带数据
            for (int i = 0; i < 4; i++) {
                writeByteList.add((byte) 0x00);
            }
        } else if (commandType == SweatConfiguration.COMMAND_TYPE_SET_FREQ) {//设置采集时间间隔,携带两位数据
            writeByteList.add((byte) 0x00);
            writeByteList.add((byte) 0x00);
            writeByteList.add((byte) 0x00);
            writeByteList.add((byte) 0x02);//数据长度2
            //具体数据
            if (sampleFre > 255 && sampleFre < 65535) {
                writeByteList.add((byte) (sampleFre / 256));
                writeByteList.add((byte) (sampleFre % 256));
            } else {
                writeByteList.add((byte) 0x00);
                writeByteList.add((byte) sampleFre);
            }
        }


        //8，校验位 1位  list还原为byte数组,添加校验和结束位后发送命令
        byte[] writeByte = new byte[writeByteList.size() + 3];
        for (int i = 0; i < writeByteList.size(); i++) {
            writeByte[i] = writeByteList.get(i);
        }
        byte crcCheck = CRC8.calcCrc8(Arrays.copyOf(writeByte, writeByte.length - 3));
        writeByte[writeByte.length - 3] = crcCheck;
        //9结束位 2位
        writeByte[writeByte.length - 2] = 0x2E;
        writeByte[writeByte.length - 1] = 0x0A;
        return writeByte;
    }


    private static ArrayList<byte[]> listData = new ArrayList<>();//存储数据(蓝牙一次接收的byte)
    private static ArrayList<byte[]> frameData = new ArrayList<>();//完整一帧的数据

    private static ArrayList<byte[]> listDataDown = new ArrayList<>();//存储数据(蓝牙一次接收的byte)
    private static ArrayList<byte[]> frameDataDown = new ArrayList<>();//完整一帧的数据

    public static synchronized ParseDataBean handleFrameDataOne(byte[] data) {
        LogUtil.e("接收数据", ProtocolParser.binaryToHexString(data) + ">>>>" + data.length);
        if (data[0] == 0x4e && data[1] == 0x46) {//"NF"代表一帧的开始
            LogUtil.e("起始");
            listData.clear();
            listData.add(data);
            return new ParseDataBean(SweatConfiguration.PARSE_TYPE_NO_NEED_HANDLE);
        } else {
            int endIndex = -1;//记录结束位置
            for (int i = 0; i < data.length; i++) {
                if (i != data.length - 1 && data[i] == 0x2e && data[i + 1] == 0x0a) {//包含结束标记
                    endIndex = i + 1;
                }
            }
            if (endIndex == -1) {
                LogUtil.e("片段");
                //片段数据
                listData.add(data);
                return new ParseDataBean(SweatConfiguration.PARSE_TYPE_NO_NEED_HANDLE);
            } else if (endIndex == data.length - 1) {//正好是2e 0a结尾
                LogUtil.e("正常结尾");
                listData.add(data);
                return handleDetailData(listData);
            } else {//特殊情况
                LogUtil.e("特殊情况");
                byte[] before = new byte[endIndex + 1];
                byte[] after = new byte[data.length - endIndex - 1];
                System.arraycopy(data, 0, before, 0, endIndex + 1);
                System.arraycopy(data, endIndex + 1, after, 0, after.length);
                listData.add(before);
                LogUtil.e("特殊情况" + ProtocolParser.binaryToHexString(before) + "\n" + ProtocolParser.binaryToHexString(after));
                frameData.clear();
                frameData.addAll(listData);
                listData.clear();
                listData.add(after);
                return handleDetailData(frameData);
            }
        }

    }

    public static synchronized ParseDataBean handleFrameDataTwo(byte[] data) {
        LogUtil.e("接收数据", ProtocolParser.binaryToHexString(data) + ">>>>" + data.length);
        if (data[0] == 0x4e && data[1] == 0x46) {//"NF"代表一帧的开始
            LogUtil.e("起始");
            listDataDown.clear();
            listDataDown.add(data);
            return new ParseDataBean(SweatConfiguration.PARSE_TYPE_NO_NEED_HANDLE);
        } else {
            int endIndex = -1;//记录结束位置
            for (int i = 0; i < data.length; i++) {
                if (i != data.length - 1 && data[i] == 0x2e && data[i + 1] == 0x0a) {//包含结束标记
                    endIndex = i + 1;
                }
            }
            if (endIndex == -1) {
                LogUtil.e("片段");
                //片段数据
                listDataDown.add(data);
                return new ParseDataBean(SweatConfiguration.PARSE_TYPE_NO_NEED_HANDLE);
            } else if (endIndex == data.length - 1) {//正好是2e 0a结尾
                LogUtil.e("正常结尾");
                listDataDown.add(data);
                return handleDetailData(listDataDown);
            } else {//特殊情况
                LogUtil.e("特殊情况");
                byte[] before = new byte[endIndex + 1];
                byte[] after = new byte[data.length - endIndex - 1];
                System.arraycopy(data, 0, before, 0, endIndex + 1);
                System.arraycopy(data, endIndex + 1, after, 0, after.length);
                listDataDown.add(before);
                LogUtil.e("特殊情况" + ProtocolParser.binaryToHexString(before) + "\n" + ProtocolParser.binaryToHexString(after));
                frameDataDown.clear();
                frameDataDown.addAll(listDataDown);
                listDataDown.clear();
                listDataDown.add(after);
                return handleDetailData(frameDataDown);
            }
        }

    }

    /**
     * 处理详细的数据
     *
     * @param bytes 数据集合
     * @return 汗液bean类的集合
     * <p>
     */
    private static ParseDataBean handleDetailData(ArrayList<byte[]> bytes) {
        ParseDataBean bean = new ParseDataBean();
        int count = 0;//获取byte总长度
        for (byte[] bs : bytes) {
            count += bs.length;
        }
        byte detailData[] = new byte[count];
        int pos = 0;
        for (byte[] bs : bytes) {
            for (byte b : bs) {
                detailData[pos++] = b;
            }
        }
        LogUtil.e("一帧数据", ProtocolParser.binaryToHexString(detailData) + ">>>>" + detailData.length);
        if (detailData.length < 34) {
            bean.setType(SweatConfiguration.PARSE_TYPE_ERROR);
            bean.setErrorMsg("小于最短长度 接收字节数: " + detailData.length);
            return bean;
        }
        if (detailData.length == 34) {
            bean.setType(SweatConfiguration.PARSE_TYPE_ERROR);
            bean.setErrorMsg("读取中...");
            return bean;
        }
        byte ddd = CRC8.calcCrc8(detailData, 0, pos - 3);
        if (ddd != detailData[detailData.length - 3]) {
            bean.setType(SweatConfiguration.PARSE_TYPE_ERROR);
            bean.setErrorMsg("校验失败");
            return bean;
        }
        //获得返回命令类型
        byte[] commandType = subByte(detailData, 23, 25);
        if (commandType[0] == 0 && commandType[1] == 3) {//温湿度数据
            return pareHumAndTemData(detailData);
        } else if (commandType[0] == 0 && commandType[1] == 4) {//频率数据
            return pareSetFreqData(detailData);
        }
        return bean;
    }

    /**
     * 解析频率命令
     *
     * @param detailData 频率命令
     * @return 解析bean
     */
    private static ParseDataBean pareSetFreqData(byte[] detailData) {
        byte[] freq = subByte(detailData, 31, 33);
        int i = freq[0] * 255 + freq[1];
        LogUtil.e("频率命令=", ProtocolParser.binaryToHexString(freq) + "解析为" + i);
        return new ParseDataBean(SweatConfiguration.PARSE_TYPE_READ_FREQ, i + "");
    }

    /**
     * 解析温湿度数据
     * 温湿度数据计算：
     * 时间点是一个 路数有多个
     */
    private static ParseDataBean pareHumAndTemData(byte[] data) {
        ParseDataBean bean = new ParseDataBean();
        bean.setType(SweatConfiguration.COMMAND_TYPE_READ_DATA);
        byte[] measureData = subByte(data, 31, data.length - 3);
        LogUtil.e("解析温湿度命令", ProtocolParser.binaryToHexString(measureData) + ">>>>" + measureData.length);
        byte[] date = subByte(measureData, 1, 7);
        String dateString = getDateFromByte(date);
        bean.setMeasureTime(dateString);
        LogUtil.e("测量时间", ProtocolParser.binaryToHexString(date) + ">>>>" + dateString);
        if (dateString.contains("1970")) {
            bean.setType(SweatConfiguration.PARSE_TYPE_ERROR);
            bean.setErrorMsg("时间1970");
            return bean;
        }
        bean.setMeasureTime(dateString);
        byte[] humAndTemData = subByte(measureData, 8, measureData.length);
        LogUtil.e("温湿度", ProtocolParser.binaryToHexString(humAndTemData) + ">>>>" + humAndTemData.length);
        List<Float> temList = new ArrayList<>();
        List<Float> humList = new ArrayList<>();
        if (humAndTemData.length % 4 != 0) {
            bean.setType(SweatConfiguration.PARSE_TYPE_ERROR);
            bean.setErrorMsg("温湿度数据自己不是4的整数倍 接收到:" + humAndTemData.length);
            return bean;
        }
        if (humAndTemData.length != 52) {
            bean.setType(SweatConfiguration.PARSE_TYPE_ERROR);
            bean.setErrorMsg("数据长度不够52" + humAndTemData.length);
            return bean;
        }
        //判断是7路还是13路,根据后6路数据是否全是零
        byte judgeChannel = 0;
        for (int i = 28; i < 52; i++) {
            judgeChannel = (byte) (judgeChannel | humAndTemData[i]);
        }
        if (judgeChannel == 0) {//全零代表是7路
            bean.setChannelNum(DOWN_MAX_CHANNEL);
        } else {//默认是13路
            bean.setChannelNum(UP_MAX_CHANNEL);
        }
        for (int i = 0; i < humAndTemData.length / 4; i++) {
//            if (i >= UP_MAX_CHANNEL) {
//                break;
//            }
            int start = i * 4;
            byte[] tem = subByte(humAndTemData, start, start + 2);
            byte[] hum = subByte(humAndTemData, start + 2, start + 4);
            float ValueTemp = changeByte(tem[0]) * 256 + changeByte(tem[1]);
            float T = 175 * ValueTemp / 65535 - 45;
            float ValueHumi = changeByte(hum[0]) * 256 + changeByte(hum[1]);
            float RH = 100 * ValueHumi / 65535;

            if (RH > 99.99) {
                RH = 99.99f;
            }
            T = (float) Math.round(T * 100) / 100;
            RH = (float) Math.round(RH * 100) / 100;
            if (T < 0) T = 00.00f;
            if (RH < RH) RH = 00.00f;
            LogUtil.e(i + 1 + "路温湿度=" + ProtocolParser.binaryToHexString(tem) + ProtocolParser.binaryToHexString(hum) + "温度=" + T + "湿度=" + RH);
            temList.add(T);
            humList.add(RH);
        }
        bean.setHumList(humList);
        bean.setTemList(temList);
        return bean;
    }

    private static String getDateFromByte(byte[] date) {
        String dateStr = "20";
        int time;
        for (byte b : date) {
            time = Integer.valueOf(String.valueOf(b), 10);
            if (time < 10) {
                dateStr = dateStr + "0" + time;
            } else {
                dateStr = dateStr + time;
            }
        }
        return dateStr;
    }

    /**
     * 截取byte数组
     */
    private static byte[] subByte(byte[] detailData, int start, int end) {
        if (detailData == null || end > detailData.length || start >= end) {
            return null;
        }
        byte b[] = new byte[end - start];
        System.arraycopy(detailData, start, b, 0, b.length);
        return b;
    }

    /**
     * 对byte变成无符号,用 int 返回
     */
    private static int changeByte(byte b) {
        return b & 0xff;
    }

    /**
     * 获取集合中的第n路湿度
     */
    public static List<Float> getHumListByChannel(List<ParseDataBean> listBean, int channel) {
        List<Float> humList = new ArrayList<>();
        if (listBean == null || listBean.size() == 0) {
            return humList;
        }
        for (int i = 0; i < listBean.size(); i++) {
            if (channel >= listBean.get(i).getHumList().size()) {
                humList.add(00.00f);
            } else {
                humList.add(listBean.get(i).getHumList().get(channel));
            }
        }
        return humList;
    }

    /**
     * 获取集合中的第n路温度
     */
    public static List<Float> getTemListByChannel(List<ParseDataBean> listBean, int channel) {
        List<Float> temList = new ArrayList<>();
        if (listBean == null || listBean.size() == 0) {
            return temList;
        }
        for (int i = 0; i < listBean.size(); i++) {
            if (channel >= listBean.get(i).getTemList().size()) {
                temList.add(00.00f);
            } else {
                temList.add(listBean.get(i).getTemList().get(channel));
            }
        }
        return temList;
    }

    /**
     * 获取上传的数据
     *
     * @param listBean 汗液bean
     * @param type     上路 下路区分
     * @return 要上传的 datas 集合
     */
    public static List<String> getUploadDatas(List<ParseDataBean> listBean, int type) {
        if (listBean == null || listBean.size() == 0) {
            return null;
        }
        List<String> datasList = new ArrayList<>();//记录数据是集合,因为可能有跨天的数据
        String timeOfDay = listBean.get(0).getTimeOfDay();
        int changeDate = -1;
        for (int i = 0; i < listBean.size(); i++) {
            if (!timeOfDay.equals(listBean.get(i).getTimeOfDay())) {
                changeDate = i;
            }
        }
        if (changeDate == -1) {
            //日期一致(绝大部分情况)
            datasList.add(getUploadString(listBean, type));
        } else {
            //出现了不一致的测量日期,这里默认最多会出现两天的情况
            datasList.add(getUploadString(new ArrayList<>(listBean.subList(0, changeDate)), type));
            datasList.add(getUploadString(new ArrayList<>(listBean.subList(changeDate, listBean.size())), type));
        }
        return datasList;
    }

    /**
     * 根据汗液数据获取上传的json串
     * * {
     * "time":"2016-12-06",
     * "list":[
     * {
     * "w":"3",
     * "v":"11:20:49,27.05,21.45;11:20:49,27.05,21.45;"
     * }
     * ]
     * }
     */
    private static String getUploadString(List<ParseDataBean> listBean, int type) {
        UploadBean uploadBean = new UploadBean();
        uploadBean.setTime(listBean.get(0).getTimeOfDay());
        int channelNumber = -1;
        if (type == SweatConfiguration.UPLOAD_TYPE_UP) {
            channelNumber = UP_MAX_CHANNEL;
        } else if (type == SweatConfiguration.UPLOAD_TYPE_DOWN) {
            channelNumber = UP_MAX_CHANNEL;
        }
        List<UploadBean.ListBean> uploadListBean = new ArrayList<>();
        for (int i = 0; i < channelNumber; i++) {
            uploadListBean.add(new UploadBean.ListBean());
        }
        //设置哪一路
        for (int j = 0; j < channelNumber; j++) {
            //设置第 j 路值
            if (type == SweatConfiguration.UPLOAD_TYPE_UP) {
                uploadListBean.get(j).setW(j + 1 + "");//路数
            } else if (type == SweatConfiguration.UPLOAD_TYPE_DOWN) {
                uploadListBean.get(j).setW(j + 14 + "");//路数
            }
        }
        ParseDataBean parseDataBean;
        String v;
        float hum;
        float tem;
        for (int i = 0; i < listBean.size(); i++) {
            parseDataBean = listBean.get(i);
            for (int j = 0; j < channelNumber; j++) {
                //设置某一路的时间点和温湿度
                v = uploadListBean.get(j).getV();
                tem = parseDataBean.getTemList().get(j);
                hum = parseDataBean.getHumList().get(j);
                if (hum == 0.0f || tem == 0.0f) {
                    uploadListBean.get(j).setV(v);
                    continue;//舍弃为零的数据
                }
                v += parseDataBean.getTimeOfhms() + "," +
                        tem + "," + hum + ";";
                uploadListBean.get(j).setV(v);
            }
        }
        //清除全零的路
        List<UploadBean.ListBean> uploadListClear = new ArrayList<>();
        for (UploadBean.ListBean b : uploadListBean) {
            if (!TextUtils.isEmpty(b.getV())) {
                uploadListClear.add(b);
            }
        }
        uploadBean.setList(uploadListClear);
        return JSONObject.toJSONString(uploadBean);
    }

    public static List<String> test() {
        List<ParseDataBean> list = new ArrayList<>();
        List<Float> data1 = new ArrayList<>();
        for (int i = 0; i < 13; i++) {
            data1.add(88.44f);
        }
        List<Float> data2 = new ArrayList<>();
        for (int i = 0; i < 13; i++) {
            data2.add(55.22f);
        }
        ParseDataBean bean;
        for (int i = 0; i < 5; i++) {
            bean = new ParseDataBean();
            bean.setMeasureTime("20170502113055");
            bean.setHumList(data1);
            bean.setTemList(data2);
            list.add(bean);
        }
        return getUploadDatas(list, SweatConfiguration.UPLOAD_TYPE_UP);
    }
}
